#pragma once
#include <string>
#include <array>
#include <vector>
#include <map>
#include <simple_enum.hpp>
#include <cereal/archives/binary.hpp>
#include <cereal/types/string.hpp>
#include <cereal/types/vector.hpp>
#include <cereal/types/array.hpp>
#include <cereal/types/map.hpp>
#include <cereal/types/memory.hpp>
#include <cereal/archives/json.hpp>










enum class Color: int32_t
{
    Red = 0,
    Green = 1,
    Blue = 2,
};


namespace simple_enum
{
namespace enum_details
{
        template <>
        inline constexpr auto names_v<Color> = std::array<std::string_view, 3>{
            "Red",
            "Green",
            "Blue",
        };

        template <>
        inline constexpr auto values_v<Color> = std::array<int32_t, 3>{
            0,
            1,
            2,
        };

        template <>
        inline constexpr auto entries_v<Color> = std::array<std::pair<std::string_view, int32_t>, 3>{
            std::pair<std::string_view, int32_t>("Red", 0),
            std::pair<std::string_view, int32_t>("Green", 1),
            std::pair<std::string_view, int32_t>("Blue", 2),
        };
} // namespace enum_details
} // namespace simple_enum

namespace cereal {
template <class Archive> inline
std::string save_minimal( Archive const &, Color const & t )
{
    std::string str(simple_enum::enum_name<Color>(t));
    return str;
}

template <class Archive> inline
void load_minimal( Archive const &, Color & t, std::string const & value )
{
    std::string_view sv(value);
    t = simple_enum::enum_cast<Color>(sv).value();
}
} // namespace cereal


enum class Texture: int32_t
{
    Silk = 0,
    Leather = 1,
    Cotton = 2,
};


namespace simple_enum
{
namespace enum_details
{
        template <>
        inline constexpr auto names_v<Texture> = std::array<std::string_view, 3>{
            "Silk",
            "Leather",
            "Cotton",
        };

        template <>
        inline constexpr auto values_v<Texture> = std::array<int32_t, 3>{
            0,
            1,
            2,
        };

        template <>
        inline constexpr auto entries_v<Texture> = std::array<std::pair<std::string_view, int32_t>, 3>{
            std::pair<std::string_view, int32_t>("Silk", 0),
            std::pair<std::string_view, int32_t>("Leather", 1),
            std::pair<std::string_view, int32_t>("Cotton", 2),
        };
} // namespace enum_details
} // namespace simple_enum

namespace cereal {
template <class Archive> inline
std::string save_minimal( Archive const &, Texture const & t )
{
    std::string str(simple_enum::enum_name<Texture>(t));
    return str;
}

template <class Archive> inline
void load_minimal( Archive const &, Texture & t, std::string const & value )
{
    std::string_view sv(value);
    t = simple_enum::enum_cast<Texture>(sv).value();
}
} // namespace cereal


class Foo
{
public:
    class Bar
    {
    public:
        enum class InnerEnum: int8_t
        {
            Good = 1,
            Bad = -1,
            Justsoso = 0,
        };



        explicit Bar(float a)
            : m_a(a){}
        // 默认构造函数 default constructor
        Bar() = default;
        // 拷贝构造函数 copy constructor
        Bar(const Bar&) = default;
        // 移动构造函数 move constructor
        Bar(Bar&&) = default;
        // 拷贝赋值运算符 copy assignment operator
        Bar& operator=(const Bar&) = default;
        // 移动赋值运算符 move assignment operator
        Bar& operator=(Bar&&) noexcept = default;
        // 析构函数 destructor
        ~Bar() = default; 
        
        inline float get_a() const { return m_a; }
        inline float& get_a_mutable() { return m_a; }
        inline void set_a(float a) { m_a = a; }


        template<class Archive>
        void serialize(Archive& archive) {
            archive(cereal::make_nvp("a", m_a));
        }

    private:
        float m_a{};
    };



    explicit Foo(float b)
        : m_b(b){}
    // 默认构造函数 default constructor
    Foo() = default;
    // 拷贝构造函数 copy constructor
    Foo(const Foo&) = default;
    // 移动构造函数 move constructor
    Foo(Foo&&) = default;
    // 拷贝赋值运算符 copy assignment operator
    Foo& operator=(const Foo&) = default;
    // 移动赋值运算符 move assignment operator
    Foo& operator=(Foo&&) noexcept = default;
    // 析构函数 destructor
    ~Foo() = default; 
    
    inline float get_b() const { return m_b; }
    inline float& get_b_mutable() { return m_b; }
    inline void set_b(float b) { m_b = b; }


    template<class Archive>
    void serialize(Archive& archive) {
        archive(cereal::make_nvp("b", m_b));
    }

private:
    float m_b{};
};


namespace simple_enum
{
namespace enum_details
{
        template <>
        inline constexpr auto names_v<Foo::Bar::InnerEnum> = std::array<std::string_view, 3>{
            "Good",
            "Bad",
            "Justsoso",
        };

        template <>
        inline constexpr auto values_v<Foo::Bar::InnerEnum> = std::array<int8_t, 3>{
            1,
            -1,
            0,
        };

        template <>
        inline constexpr auto entries_v<Foo::Bar::InnerEnum> = std::array<std::pair<std::string_view, int8_t>, 3>{
            std::pair<std::string_view, int8_t>("Good", 1),
            std::pair<std::string_view, int8_t>("Bad", -1),
            std::pair<std::string_view, int8_t>("Justsoso", 0),
        };
} // namespace enum_details
} // namespace simple_enum

namespace cereal {
template <class Archive> inline
std::string save_minimal( Archive const &, Foo::Bar::InnerEnum const & t )
{
    std::string str(simple_enum::enum_name<Foo::Bar::InnerEnum>(t));
    return str;
}

template <class Archive> inline
void load_minimal( Archive const &, Foo::Bar::InnerEnum & t, std::string const & value )
{
    std::string_view sv(value);
    t = simple_enum::enum_cast<Foo::Bar::InnerEnum>(sv).value();
}
} // namespace cereal







